﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

using LowLevelGraphics.Histograms;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    ///  This Filter does:
    ///  1.  generates a background image estimated through iterations
    ///  of the minimum ranking and the number of iterations is defined
    ///  by the user;
    ///  2.  substracts the background image from the orginal image
    ///  and generates a result image.
    ///  3.  auto-contrast the result image.    
    /// </summary>
    public class BackgroundCorrection : BaseImageFilter
    {
        protected bool m_bAutoContrast = true;
        protected int m_nNumberIteration = 1;
        protected int m_nRadius = -1;

        protected Ranking m_RankingFilter = new Ranking();
        protected And m_AndFilter = new And();
        
        /// <summary>
        /// default constructor
        /// </summary>
        public BackgroundCorrection()
        {
        }

        /// <summary>
        /// used by clone to create a deep copy
        /// </summary>
        /// <param name="_backgroundCorrection"></param>
        internal BackgroundCorrection(BackgroundCorrection _backgroundCorrection)
        {
            this.m_bAutoContrast = _backgroundCorrection.m_bAutoContrast;
            this.m_nNumberIteration = _backgroundCorrection.m_nNumberIteration;
            this.m_nRadius = _backgroundCorrection.m_nRadius;
        }

        /// <summary>
        /// Sets or gets autocontrast
        /// </summary>
        public bool AutoContrast
        {
            get { return m_bAutoContrast; }
            set { m_bAutoContrast = value; }
        }

        /// <summary>
        /// Gets or sets radius
        /// </summary>
        public int Radius
        {
            get { return m_nRadius; }
            set { m_nRadius = value; }
        }

        /// <summary>
        /// gets or sets number of iterations
        /// </summary>
        public int NumberIteration
        {
            get { return m_nNumberIteration; }
            set { m_nNumberIteration = value; }
        }

        /// <summary>
        /// executes this filter
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bitmapBackground = (UnsafeBitmap)_bitmap.Clone();
            EstimateBackground(bitmapBackground, m_nNumberIteration, m_nRadius);
            if (m_bAutoContrast) AutoAdjust(bitmapBackground);
            UnsafeBitmap bitmap = m_AndFilter.Process(bitmapBackground, _bitmap);
            
            BitmapFunctions.Copy(bitmap, _bitmap);
            return _bitmap;
        }

        /// <summary>
        /// Estimates the background.
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <param name="iteration">The iteration.</param>
        /// <param name="radius">The radius.</param>
        protected virtual void EstimateBackground(UnsafeBitmap _bitmap, int iteration, int radius)
        {
            for (int i = 1; i <= iteration; i++)
            {
                m_RankingFilter.Execute(_bitmap);
            }
        }

        /// <summary>
        /// Autoes the adjust.
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        protected void AutoAdjust(UnsafeBitmap _bitmap)
        {
            Rectangle roi = Rectangle.Empty;

            double min, max;
            Statistics histogram = new Statistics(_bitmap);
            histogram.SortBy(PROCESSING_MODE.Color);
            int threshold = _bitmap.Width * _bitmap.Height / 5000;
            int i = -1;
            bool found = false;
            do
            {
                i++;
                found = histogram[i].ColorValue > threshold;
            } while (!found && i < 255);
            int hmin = i;
            i = 256;
            do
            {
                i--;
                found = histogram[i].ColorValue > threshold;
            } while (!found && i > 0);
            int hmax = i;

            int histMin = ColorFunctions.ToIntRGB(histogram.ColorList[0].Key);
            if (hmax > hmin)
            {
                roi = Rectangle.Empty;
                min = histMin + hmin * 1; //min = histMin + hmin * stats.binSize;
                max = histMin + hmax * 1; //max = histMin + hmax * stats.binSize;
            }
        }
        /// <summary>
        /// used to create a deep copy
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new BackgroundCorrection(this);
        }
    }
}
